// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');
const { exec } = require('child_process');
const { promisify } = require('util');
const path = require('path');

const execAsync = promisify(exec);

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed

/**
 * @param {vscode.ExtensionContext} context
 */
function activate(context) {
	console.log('扩展 "filter-git-commit" 已激活!');

	// 注册显示Git提交记录的命令
	let showGitCommitsCommand = vscode.commands.registerCommand('filter-git-commit.showCommits', async function () {
		// 显示加载提示
		const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
		statusBarItem.text = "$(sync~spin) 正在加载Git提交记录...";
		statusBarItem.show();

		try {
			// 检查是否在扩展开发主机中或没有打开任何工作区
			const workspaceFolders = vscode.workspace.workspaceFolders;
			const needSelectFolder = !workspaceFolders || workspaceFolders.length === 0;
			let workspacePath;

			if (needSelectFolder) {
				// 让用户选择一个项目文件夹
				const folderUri = await vscode.window.showOpenDialog({
					canSelectFiles: false,
					canSelectFolders: true,
					canSelectMany: false,
					openLabel: '选择Git项目文件夹'
				});

				if (!folderUri || folderUri.length === 0) {
					vscode.window.showInformationMessage('请选择一个Git项目文件夹进行测试');
					statusBarItem.hide();
					return;
				}

				workspacePath = folderUri[0].fsPath;
				vscode.window.showInformationMessage(`已选择文件夹: ${path.basename(workspacePath)}`);
			} else {
				// 正常模式，选择工作区
				workspacePath = await selectWorkspace();
				if (!workspacePath) {
					statusBarItem.hide();
					return; // 用户取消了选择工作区
				}
			}

			// 检查是否是Git仓库
			try {
				statusBarItem.text = "$(sync~spin) 检查Git仓库...";
				const { stdout } = await execAsync('git rev-parse --is-inside-work-tree', { cwd: workspacePath });
				if (stdout.trim() !== 'true') {
					throw new Error('不是有效的Git仓库');
				}
			} catch (error) {
				vscode.window.showErrorMessage(`当前目录不是Git仓库: ${workspacePath}`);
				statusBarItem.hide();
				return;
			}

			// 获取筛选条件
			statusBarItem.text = "$(sync~spin) 准备筛选条件...";
			const filters = await getFilters(workspacePath);
			if (!filters) {
				statusBarItem.hide();
				return; // 用户取消了
			}

			// 构建git log命令
			const gitLogCommand = buildGitLogCommand(filters);

			// 执行git命令
			statusBarItem.text = "$(sync~spin) 获取Git提交记录...";

			// 使用withProgress显示进度
			await vscode.window.withProgress({
				location: vscode.ProgressLocation.Notification,
				title: "获取Git提交记录",
				cancellable: false
			}, async (progress) => {
				progress.report({ increment: 30, message: "执行Git命令..." });

				try {
					const { stdout, stderr } = await execAsync(gitLogCommand, { cwd: workspacePath });

					if (stderr && !stdout) {
						vscode.window.showErrorMessage(`Git错误: ${stderr}`);
						statusBarItem.hide();
						return;
					}

					progress.report({ increment: 30, message: "处理结果..." });

					// 显示结果
					statusBarItem.text = "$(sync~spin) 生成结果页面...";
					const panel = vscode.window.createWebviewPanel(
						'gitCommits',
						'Git提交记录',
						vscode.ViewColumn.One,
						{
							enableScripts: true
						}
					);

					// 处理Webview消息
					panel.webview.onDidReceiveMessage(async message => {
						if (message.command === 'getCommitFiles') {
							try {
								const files = await getCommitFiles(message.hash, workspacePath);
								panel.webview.postMessage({
									command: 'showCommitFiles',
									hash: message.hash,
									files: files
								});
							} catch (error) {
								console.error('获取文件列表失败:', error);
								panel.webview.postMessage({
									command: 'showCommitFiles',
									hash: message.hash,
									files: [],
									error: error.message
								});
							}
						}
					});

					progress.report({ increment: 40, message: "生成页面..." });

					// 格式化输出
					panel.webview.html = getWebviewContent(stdout, filters, path.basename(workspacePath));

					// 隐藏状态栏
					statusBarItem.hide();

					// 提交数量
					const commits = stdout.split('\n').filter(line => line.trim().length > 0);
					if (commits.length === 0) {
						vscode.window.showInformationMessage('未找到符合条件的提交记录');
					} else {
						vscode.window.showInformationMessage(`找到 ${commits.length} 条提交记录`);
					}
				} catch (error) {
					vscode.window.showErrorMessage(`发生错误: ${error.message}`);
					statusBarItem.hide();
				}
			});

		} catch (error) {
			vscode.window.showErrorMessage(`发生错误: ${error.message}`);
			statusBarItem.hide();
		}
	});

	context.subscriptions.push(showGitCommitsCommand);
}

/**
 * 选择工作区
 * @returns {Promise<string|undefined>} 返回选中的工作区路径
 */
async function selectWorkspace() {
	const workspaceFolders = vscode.workspace.workspaceFolders;

	// 无工作区检查在调用此函数前已完成，这里不应该出现无工作区的情况
	if (!workspaceFolders || workspaceFolders.length === 0) {
		return undefined;
	}

	// 如果只有一个工作区，直接返回
	if (workspaceFolders.length === 1) {
		return workspaceFolders[0].uri.fsPath;
	}

	// 如果有多个工作区，让用户选择
	const workspaceOptions = workspaceFolders.map(folder => ({
		label: folder.name,
		description: folder.uri.fsPath,
		path: folder.uri.fsPath
	}));

	const selectedWorkspace = await vscode.window.showQuickPick(workspaceOptions, {
		placeHolder: '选择要筛选Git记录的工作区'
	});

	return selectedWorkspace ? selectedWorkspace.path : undefined;
}

/**
 * 获取Git项目中的所有提交者列表
 * @param {string} workspacePath 工作区路径
 * @param {object} [options] 可选参数
 * @param {number} [options.limit] 限制返回的提交者数量，默认为50
 * @returns {Promise<Array<string>>} 提交者列表
 */
async function getCommitters(workspacePath, options = {}) {
	try {
		// 默认限制为50个提交者，避免列表过长
		const limit = options.limit || 50;

		// 使用更可靠的命令格式
		const command = `git log --pretty=format:"%an" --all | sort | uniq${limit ? ` | head -n ${limit}` : ''}`;

		// 使用超时设置避免长时间阻塞
		const { stdout } = await execAsync(command, {
			cwd: workspacePath,
			timeout: 10000, // 10秒超时
			shell: 'cmd.exe' // Windows上使用cmd.exe
		});

		const committers = stdout.split('\n')
			.map(line => line.trim())
			.filter(line => line.length > 0);

		// 如果获取不到提交者，尝试从邮箱获取
		if (committers.length === 0) {
			console.log('尝试从邮箱获取提交者...');
			const { stdout: emailOutput } = await execAsync(
				'git log --pretty=format:"%ae" --all | sort | uniq',
				{
					cwd: workspacePath,
					timeout: 5000,
					shell: 'cmd.exe'
				}
			);

			const emailUsers = emailOutput.split('\n')
				.map(email => {
					// 尝试从邮箱提取用户名部分
					const match = email.match(/^([^@]+)@/);
					return match ? match[1] : email;
				})
				.filter(name => name.length > 0);

			return [...new Set(emailUsers)].slice(0, limit);
		}

		console.log(`找到 ${committers.length} 个提交者`);
		return committers;
	} catch (error) {
		console.error('获取提交者列表失败:', error);
		// 尝试使用备用命令
		try {
			const { stdout } = await execAsync(
				'git shortlog -sn --all',
				{
					cwd: workspacePath,
					timeout: 5000,
					shell: 'cmd.exe'
				}
			);

			const committers = stdout.split('\n')
				.map(line => {
					const match = line.match(/\s+(.+)$/);
					return match ? match[1].trim() : '';
				})
				.filter(name => name.length > 0);

			console.log(`使用备用命令找到 ${committers.length} 个提交者`);
			return committers.slice(0, options.limit || 50);
		} catch (backupError) {
			console.error('备用命令也失败了:', backupError);
			return [];
		}
	}
}

/**
 * 获取用户输入的筛选条件
 * @param {string} workspacePath 工作区路径
 * @returns {Promise<object|undefined>} 返回筛选条件对象
 */
async function getFilters(workspacePath) {
	// 获取分支列表
	let branches = [];
	try {
		const { stdout } = await execAsync('git branch', { cwd: workspacePath });
		branches = stdout.split('\n')
			.map(b => b.trim())
			.filter(b => b.length > 0)
			.map(b => b.startsWith('* ') ? b.substring(2) : b);

		// 添加远程分支
		const { stdout: remoteOutput } = await execAsync('git branch -r', { cwd: workspacePath });
		const remoteBranches = remoteOutput.split('\n')
			.map(b => b.trim())
			.filter(b => b.length > 0 && !b.includes(' -> '));

		branches = [...branches, ...remoteBranches];
	} catch (error) {
		console.error('获取分支列表失败:', error);
	}

	// 选择时间类型
	const timeTypeOptions = ['不限时间', '指定日期', '日期范围'];
	const selectedTimeType = await vscode.window.showQuickPick(timeTypeOptions, {
		placeHolder: '选择时间筛选类型'
	});

	if (!selectedTimeType) return;

	let startDate = null;
	let endDate = null;

	if (selectedTimeType === '指定日期') {
		const dateInput = await vscode.window.showInputBox({
			placeHolder: '输入日期 (YYYY-MM-DD)'
		});
		if (!dateInput) return;
		startDate = dateInput;
	} else if (selectedTimeType === '日期范围') {
		const startDateInput = await vscode.window.showInputBox({
			placeHolder: '输入开始日期 (YYYY-MM-DD)'
		});
		if (!startDateInput) return;

		const endDateInput = await vscode.window.showInputBox({
			placeHolder: '输入结束日期 (YYYY-MM-DD)'
		});
		if (!endDateInput) return;

		startDate = startDateInput;
		endDate = endDateInput;
	}

	// 选择分支
	const branchOptions = ['所有分支', ...branches];
	const selectedBranch = await vscode.window.showQuickPick(branchOptions, {
		placeHolder: '选择分支'
	});

	if (!selectedBranch) return;

	// 获取提交者列表
	const committers = await getCommitters(workspacePath, { limit: 100 });

	// 创建QuickPick选项
	let author = null;
	if (committers.length > 0) {
		// 构建选项，添加"所有人"和"手动输入"选项
		const committerOptions = [
			{
				label: '$(group-by-ref-type) 所有人',
				description: '不按提交人筛选',
				detail: '显示所有人的提交记录',
				value: null,
				sortOrder: 0
			},
			{
				label: '$(edit) 手动输入',
				description: '输入其他提交人',
				detail: '输入未在列表中的提交人名称',
				value: 'MANUAL_INPUT',
				sortOrder: 1
			},
			...committers.map((c, index) => ({
				label: `$(person) ${c}`,
				description: '项目提交者',
				detail: `只显示 ${c} 的提交记录`,
				value: c,
				sortOrder: index + 2
			}))
		];

		// 创建QuickPick界面
		const quickPick = vscode.window.createQuickPick();
		quickPick.items = committerOptions;
		quickPick.placeholder = '选择或输入提交人 (↑↓选择，Enter确认)';
		quickPick.matchOnDescription = true;
		quickPick.matchOnDetail = true;

		// 使用Promise封装QuickPick选择
		const selectedCommitter = await new Promise((resolve) => {
			quickPick.onDidAccept(() => {
				resolve(quickPick.selectedItems[0]);
				quickPick.hide();
			});

			quickPick.onDidHide(() => {
				resolve(null);
			});

			quickPick.show();
		});

		if (!selectedCommitter) return; // 用户取消了选择

		if (selectedCommitter.value === 'MANUAL_INPUT') {
			// 用户选择了手动输入，弹出输入框
			const manualAuthor = await vscode.window.showInputBox({
				placeHolder: '输入提交人名称',
				prompt: '输入Git提交者的姓名，将精确匹配'
			});
			if (manualAuthor === undefined) return; // 用户取消了输入
			author = manualAuthor || null; // 空字符串转为null
		} else {
			author = selectedCommitter.value;
		}
	} else {
		// 如果无法获取提交者列表，退回到传统输入框
		const inputAuthor = await vscode.window.showInputBox({
			placeHolder: '输入提交人 (为空则不筛选)',
			prompt: '未找到历史提交者，请手动输入'
		});
		if (inputAuthor === undefined) return; // 用户取消了输入
		author = inputAuthor || null;
	}

	return {
		timeType: selectedTimeType,
		startDate,
		endDate,
		branch: selectedBranch === '所有分支' ? null : selectedBranch,
		author
	};
}

/**
 * 构建git log命令
 * @param {object} filters 筛选条件
 * @returns {string} git log命令
 */
function buildGitLogCommand(filters) {
	let command = 'git log --pretty=format:"%h | %an | %ad | %s" --date=short';

	// 限制显示数量，防止获取太多记录
	command += ' -100';

	// 添加时间筛选
	if (filters.timeType === '指定日期') {
		command += ` --since="${filters.startDate} 00:00:00" --until="${filters.startDate} 23:59:59"`;
	} else if (filters.timeType === '日期范围') {
		command += ` --since="${filters.startDate} 00:00:00" --until="${filters.endDate} 23:59:59"`;
	}

	// 添加作者筛选
	if (filters.author) {
		command += ` --author="${filters.author}"`;
	}

	// 添加分支筛选
	if (filters.branch) {
		command += ` ${filters.branch}`;
	} else {
		// 如果未指定分支，默认使用所有分支
		command += ' --all';
	}

	return command;
}

/**
 * 获取提交的文件变更列表
 * @param {string} commitHash 提交哈希
 * @param {string} workspacePath 工作区路径
 * @returns {Promise<Array<{type: string, path: string}>>} 文件列表
 */
async function getCommitFiles(commitHash, workspacePath) {
	try {
		const { stdout } = await execAsync(`git show --name-status --oneline ${commitHash}`, { cwd: workspacePath });
		// 跳过第一行（commit信息）,提取文件变更信息
		const lines = stdout.split('\n').slice(1).filter(line => line.trim());
		return lines.map(line => {
			const parts = line.split('\t');
			if (parts.length >= 2) {
				const changeType = parts[0];
				const filePath = parts.slice(1).join('\t');
				let changeTypeDesc = '';

				switch(changeType.charAt(0)) {
					case 'A': changeTypeDesc = '新增'; break;
					case 'M': changeTypeDesc = '修改'; break;
					case 'D': changeTypeDesc = '删除'; break;
					case 'R': changeTypeDesc = '重命名'; break;
					case 'C': changeTypeDesc = '复制'; break;
					default: changeTypeDesc = changeType;
				}

				return { type: changeTypeDesc, path: filePath };
			}
			return null;
		}).filter(item => item);
	} catch (error) {
		console.error('获取提交文件列表失败:', error);
		return [];
	}
}

/**
 * 生成Webview内容
 * @param {string} gitOutput git命令输出
 * @param {object} filters 使用的筛选条件
 * @param {string} workspaceName 工作区名称
 * @returns {string} HTML内容
 */
function getWebviewContent(gitOutput, filters, workspaceName) {
	const commits = gitOutput.split('\n').filter(line => line.trim().length > 0);

	let filterInfo = '筛选条件: ';
	if (filters.timeType === '指定日期') {
		filterInfo += `日期: ${filters.startDate}; `;
	} else if (filters.timeType === '日期范围') {
		filterInfo += `日期范围: ${filters.startDate} 至 ${filters.endDate}; `;
	} else {
		filterInfo += `时间: 不限; `;
	}

	if (filters.branch) {
		filterInfo += `分支: ${filters.branch}; `;
	} else {
		filterInfo += `分支: 所有分支; `;
	}

	if (filters.author) {
		filterInfo += `提交人: ${filters.author}; `;
	} else {
		filterInfo += `提交人: 所有人; `;
	}

	return `
		<!DOCTYPE html>
		<html lang="zh-CN">
		<head>
			<meta charset="UTF-8">
			<meta name="viewport" content="width=device-width, initial-scale=1.0">
			<title>Git提交记录</title>
			<style>
				body {
					font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
					padding: 0 20px;
					color: var(--vscode-foreground);
					background-color: var(--vscode-editor-background);
				}
				.header {
					margin-bottom: 20px;
					padding-bottom: 10px;
					border-bottom: 1px solid var(--vscode-panel-border);
				}
				.project-name {
					color: var(--vscode-textLink-activeForeground);
					font-weight: bold;
				}
				.commit {
					margin-bottom: 15px;
					padding: 10px;
					background-color: var(--vscode-editor-inactiveSelectionBackground);
					border-radius: 5px;
				}
				.hash {
					font-family: monospace;
					color: var(--vscode-textLink-foreground);
					cursor: pointer;
				}
				.hash:hover {
					text-decoration: underline;
				}
				.author {
					font-weight: bold;
					color: var(--vscode-editor-foreground);
				}
				.date {
					color: var(--vscode-descriptionForeground);
				}
				.message {
					margin-top: 5px;
				}
				.empty {
					color: var(--vscode-errorForeground);
					font-style: italic;
				}
				.filter-box {
					background-color: var(--vscode-dropdown-background);
					padding: 10px;
					border-radius: 5px;
					margin-bottom: 10px;
				}
				.files-container {
					display: none;
					margin-top: 10px;
					padding: 5px;
					background-color: var(--vscode-dropdown-listBackground);
					border-radius: 3px;
				}
				.file-item {
					font-family: monospace;
					padding: 3px;
				}
				.file-added {
					color: var(--vscode-gitDecoration-addedResourceForeground, #81b88b);
				}
				.file-modified {
					color: var(--vscode-gitDecoration-modifiedResourceForeground, #e2c08d);
				}
				.file-deleted {
					color: var(--vscode-gitDecoration-deletedResourceForeground, #c74e39);
				}
				.file-renamed {
					color: var(--vscode-gitDecoration-renamedResourceForeground, #73c991);
				}
				.error-message {
					color: var(--vscode-errorForeground);
					background-color: var(--vscode-inputValidation-errorBackground);
					border: 1px solid var(--vscode-inputValidation-errorBorder);
					padding: 5px;
					border-radius: 3px;
					margin-top: 5px;
				}
			</style>
		</head>
		<body>
			<div class="header">
				<h2>Git提交记录 - <span class="project-name">${workspaceName}</span></h2>
				<div class="filter-box">${filterInfo}</div>
				<div>总共找到 ${commits.length} 条提交记录</div>
			</div>

			<div class="commits">
				${commits.length === 0 ? '<div class="empty">未找到符合条件的提交记录</div>' : ''}
				${commits.map(commit => {
					const parts = commit.split(' | ');
					if (parts.length < 4) return '';

					const hash = parts[0];
					const author = parts[1];
					const date = parts[2];
					const message = parts.slice(3).join(' | ');

					return `
						<div class="commit">
							<div>
								<span class="hash" onclick="toggleFiles('${hash}')">${hash}</span> -
								<span class="author">${author}</span> -
								<span class="date">${date}</span>
							</div>
							<div class="message">${message}</div>
							<div id="files-${hash}" class="files-container"></div>
						</div>
					`;
				}).join('')}
			</div>

			<script>
				const vscode = acquireVsCodeApi();

				function toggleFiles(hash) {
					const container = document.getElementById('files-' + hash);

					if (container.style.display === 'block') {
						container.style.display = 'none';
						return;
					}

					if (container.innerHTML.trim() === '') {
						container.textContent = '加载中...';
						container.style.display = 'block';

						vscode.postMessage({
							command: 'getCommitFiles',
							hash: hash
						});
					} else {
						container.style.display = 'block';
					}
				}

				window.addEventListener('message', event => {
					const message = event.data;

					if (message.command === 'showCommitFiles') {
						const container = document.getElementById('files-' + message.hash);
						container.innerHTML = '';

						if (message.error) {
							const errorDiv = document.createElement('div');
							errorDiv.classList.add('error-message');
							errorDiv.textContent = '错误: ' + message.error;
							container.appendChild(errorDiv);
							return;
						}

						if (message.files.length === 0) {
							container.textContent = '无文件变更';
							return;
						}

						message.files.forEach(file => {
							const div = document.createElement('div');
							div.classList.add('file-item');

							// 添加适当的CSS类
							switch(file.type) {
								case '新增': div.classList.add('file-added'); break;
								case '修改': div.classList.add('file-modified'); break;
								case '删除': div.classList.add('file-deleted'); break;
								case '重命名': div.classList.add('file-renamed'); break;
							}

							div.textContent = \`[\${file.type}] \${file.path}\`;
							container.appendChild(div);
						});
					}
				});
			</script>
		</body>
		</html>
	`;
}

// This method is called when your extension is deactivated
function deactivate() {}

module.exports = {
	activate,
	deactivate
}
